﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace MetaDemo.Tabs
{
    public partial class ObjectMethods : UserControl
    {
        public static TabPage Get(Object o)
        {
            // Display information on the object.
            var methods = new ObjectMethods();

            methods.grdMethods.AutoGenerateColumns = false;

            // Bind the fields to the columns
            var bs = new BindingSource();
            bs.DataSource = MethodInstance.GetInstances(o);
            methods.grdMethods.DataSource = bs;

            // Create a tab page in which to display the information above.
            var page = GetTabPage();
            page.Controls.Add(methods);

            return page;
        }

        public static TabPage GetTabPage()
        {
            var page = new TabPage();

            page.Location = new System.Drawing.Point(4, 22);
            page.Name = "tabMethods";
            page.Padding = new System.Windows.Forms.Padding(3);
            page.Size = new System.Drawing.Size(428, 391);
            page.Text = "Methods";
            page.UseVisualStyleBackColor = true;

            return page;
        }

        public ObjectMethods()
        {
            InitializeComponent();
        }

        private void grdMethods_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView view = sender as DataGridView;
            if (0 > e.RowIndex || view.Rows.Count <= e.RowIndex)
                return;

            var methodInstance = (MethodInstance)view.Rows[e.RowIndex].DataBoundItem;
            if (1 == e.ColumnIndex)
            {
                // Return type has been clicked: Forward navigation to the field's type object!
                Forms.ObjectInfoForm.Get(methodInstance.Info.ReturnType).Show();
            }
            else if (4 == e.ColumnIndex)
            {
                // Invoke button has been clicked.
                var mi = methodInstance.Info;
                if (1 < mi.GetParameters().Count()
                    || (1 == mi.GetParameters().Count()
                        && !mi.GetParameters()[0].ParameterType.IsArray
                        && !mi.GetParameters()[0].ParameterType.IsPointer))
                {
                    MessageBox.Show("Cannot invoke methods with mandatory arguments.");
                    return;
                }

                methodInstance.Info.Invoke(methodInstance.Parent, null);
            }
        }





        public class MethodInstance
        {
            public static List<MethodInstance> GetInstances(Object obj)
            {
                var list = new List<MethodInstance>();

                // Fields
                foreach (MethodInfo mi in obj.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
                {
                    list.Add(new MethodInstance(obj, mi));
                }

                return list;
            }


            private Object parent;
            public Object Parent { get { return parent; } }

            private MethodInfo methodInfo;

            public MethodInstance(Object p, MethodInfo mi)
            {
                parent = p;
                methodInfo = mi;
            }

            public String MethodName { get { return methodInfo.Name; } }

            public String ReturnType { get { return methodInfo.ReturnType.ToString(); } }

            public String Modifier {
                get
                {
                    var l = new List<String>();
                    if (methodInfo.IsPrivate) l.Add("private");
                    if (methodInfo.IsFamily) l.Add("protected");
                    if (methodInfo.IsAssembly) l.Add("internal");
                    if (methodInfo.IsPublic) l.Add("public");
                    if (methodInfo.IsAbstract) l.Add("abstract");
                    if (methodInfo.IsVirtual) l.Add("virtual");
                    if (methodInfo.IsFinal) l.Add("final");
                    if (methodInfo.IsStatic) l.Add("static");

                    var s = "";
                    foreach (var modifier in l)
                    {
                        if ("" != s) s += ", ";
                        s += modifier;
                    }
                    return s;
                }
            }

            public String Arguments {
                get
                {
                    if (0 == methodInfo.GetParameters().Count())
                        return "<none>";

                    String s = "";
                    foreach (var p in methodInfo.GetParameters())
                    {
                        if ("" != s)
                            s += ", ";
                        s += p.ParameterType.Name;
                    }
                    return s;
                }
            }

            public String MethodInvoke { get { return "Invoke"; } }

            public MethodInfo Info { get { return methodInfo; } }
        }

    }
}
